﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using System.Windows;
using FFmpegVideoClip.Configuration;
using FFmpegVideoClip.Lib.AdvancedFragmentProcessor;
using FFmpegVideoClip.Lib.AdvancedFragmentProcessor.InternalProcessor;
using FFmpegVideoClip.Lib.Afterprocessings;
using FFmpegVideoClip.Lib.ClipGroups;
using FFmpegVideoClip.Mode;
using FFmpegVideoClip.Mode.Files;
using UtilityToolsCollect.ObjectsLibrary.ProcessManage;
using UtilityToolsCollect.WinSystemUtilityTools;

namespace FFmpegVideoClip.Lib
{

    internal class TaskWorkersManage : TaskScheduler, IDisposable
    {
        private enum TaskMessageEnum { AddTask, Remove, Clear, Sort, ExecuteTask }
        private readonly record struct TaskMessage(TaskMessageEnum MessageType, Task? TaskObject);
        private static readonly TimeSpan TasksMaximumIdleTime = TimeSpan.FromSeconds(5);

        public event EventHandler? OnCompleted;
        private int m_MaximumConcurrencyLevel;
        public override int MaximumConcurrencyLevel => m_MaximumConcurrencyLevel;
        private DateTime? PollingTaskStartTime;
        private TimeSpan RuningTime => PollingTaskStartTime is null ? TimeSpan.Zero : DateTime.Now - PollingTaskStartTime.Value;

        private Channel<TaskMessage>? taskMessages;
        private List<Task>? TaskQueue = new();
        protected override IEnumerable<Task>? GetScheduledTasks() => TaskQueue?.ToImmutableArray() ?? [];
        private ConcurrentDictionary<Task, int>? TaskQueueDic = new();
        private ConcurrentDictionary<Task, int>? RuningTasks = new();
        public bool IsActive => !disposedValue && !Tools.IsCancellationRequested;

        private PeriodicTimer PollingTask;
        private CpuPerformanceCount? _cpuPerformanceCount;
        private float[]? _cpuPerformanceCountValues;
        private int CpuPerformanceCountIndex = 0;
        public float CpuPerformanceAverage
        {
            get
            {
                IEnumerable<float>? temp = _cpuPerformanceCountValues?.Where(p => p > 0);
                if (temp?.Any() != true)
                    return -1;
                return temp.Average();
            }
        }
        private bool IsCpuLimit
        {
            get
            {
                if (_cpuPerformanceCountValues == null)
                    return false;
                AddCpuPerformanceCount();
                try
                {
                    float cpuAverageValue = CpuPerformanceAverage;
                    return (cpuAverageValue > 0 ? cpuAverageValue : float.MaxValue) > Config.CpuPerformanceLimit;
                }
                catch (InvalidOperationException)
                { return true; }
            }
        }
        private void AddCpuPerformanceCount()
        {
            if (_cpuPerformanceCount is null)
                return;
            float value = _cpuPerformanceCount.Value;
            if (value < 1)
                return;
            _cpuPerformanceCountValues?[CpuPerformanceCountIndex] = value;
            CpuPerformanceCountIndex = (CpuPerformanceCountIndex + 1) % (_cpuPerformanceCountValues?.Length ?? Config.CpuPerformanceCountCache);
        }


        public TaskWorkersManage()
        {

            m_MaximumConcurrencyLevel = Config.MaxThread;

            _cpuPerformanceCountValues = new float[Config.CpuPerformanceCountCache];
            _cpuPerformanceCount = CpuPerformanceCount.Create(CpuPerformanceCount.PerformanceCountTypeEnum.InformationProcessorTime);
            _ = _cpuPerformanceCount.Value;
            taskMessages = Channel.CreateUnbounded<TaskMessage>();
            PollingTask = new PeriodicTimer(TimeSpan.FromMilliseconds(Config.TaskPollingInterval));

            Task.Run(MainWorkerThreadProc, Tools.CurrentCancelToken!.Token);
            Task.Run(Polling, Tools.CurrentCancelToken.Token);
            LogManage.WriteLineNewInfo($"调度信息：调度器启动");
        }
        public async Task MainWorkerThreadProc()
        {
            try
            {
                while (await taskMessages!.Reader.WaitToReadAsync(Tools.CurrentCancelToken!.Token) && !Tools.IsCancellationRequested && !disposedValue)
                {
                    LogManage.WriteLineNewInfo($"调度信息：{nameof(MainWorkerThreadProc)},消息轮询");
                    AddCpuPerformanceCount();
                    if (taskMessages.Reader.TryRead(out TaskMessage msg))
                    {
                        LogManage.WriteLineNewInfo($"调度信息：{nameof(MainWorkerThreadProc)},消息轮询，取出消息{msg.MessageType}:[{msg.TaskObject?.Id}]");
                        switch (msg.MessageType)
                        {
                            case TaskMessageEnum.AddTask:
                                AddTask(msg.TaskObject!);
                                break;
                            case TaskMessageEnum.Remove:
                                RemoveTask(msg.TaskObject!);
                                break;
                            case TaskMessageEnum.Clear:
                                _Clear();
                                break;
                            case TaskMessageEnum.Sort:
                                _Sort();
                                break;
                            default:
                                ExecuteNextTask();
                                break;
                        }
                    }
                }
            }
            catch (OperationCanceledException) { }
            catch (Exception ex)
            {
                LogManage.WriteExceptionInfo($"{nameof(MainWorkerThreadProc)} 异常:", ex);
            }
        }
        
        private void ExecuteNextTask()
        {
            LogManage.WriteLineNewInfo($"调度信息：{nameof(ExecuteNextTask)}[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务");
            if (!IsActive || Tools.IsCancellationRequested || ((RuningTasks?.Count ?? 0) < 1 && (TaskQueue?.Count ?? 0) < 1 && RuningTime > TasksMaximumIdleTime))
            {
                LogManage.WriteLineNewInfo($"调度信息：{nameof(ExecuteNextTask)}:调度器释放：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务");
                OnCompleted?.Invoke(this, new EventArgs());
                return;
            }
            if (!IsActive || (RuningTasks?.Count ?? 0) >= MaximumConcurrencyLevel || IsCpuLimit || !TakeOneTask(out Task? TakeTask))
                    return;

            RuningTasks?.TryAdd(TakeTask!, default);
            if (LimitedParallelPerformanceTaskScheduler.IsThreadStartSupported && (TakeTask!.CreationOptions & TaskCreationOptions.LongRunning) != 0)
            {
                LogManage.WriteLineNewInfo($"调度信息：{nameof(ExecuteNextTask)}:准备执行任务[{TakeTask.Id}]-[独立线程]：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务");
                new Thread(() => ExecuteTask(TakeTask)) { IsBackground = true, Name = "BackgroundThread" }.UnsafeStart();
            }
            else
            {
                LogManage.WriteLineNewInfo($"调度信息：{nameof(ExecuteNextTask)}:准备执行任务[{TakeTask?.Id}]-[发送到线程池]：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务");
                ThreadPool.UnsafeQueueUserWorkItem(_ => ExecuteTask(TakeTask!), (TakeTask!.CreationOptions & TaskCreationOptions.PreferFairness) == 0);
            }
        }
        private void ExecuteTask(Task task)
        {
            if (task is null) return;
            LogManage.WriteLineNewInfo($"调度信息：{nameof(ExecuteTask)}:开始执行任务[{task.Id}]：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务");
            try { TryExecuteTask(task); }
            catch (OperationCanceledException) { }
            catch (AggregateException aex) { LogManage.WriteExceptionInfo($"调度信息：{nameof(ExecuteTask)}:任务异常[{nameof(AggregateException)}][{task.Id}]：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务", aex); }
            catch (ObjectDisposedException‌) { }
            catch (Exception ex) { LogManage.WriteExceptionInfo($"调度信息：{nameof(ExecuteTask)}:任务异常[{task.Id}]：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务", ex); }
            finally
            {
                LogManage.WriteLineNewInfo($"调度信息：{nameof(ExecuteTask)}:[完成][{task.Id}]：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务");
                if (IsActive)
                {
                    RuningTasks?.TryRemove(task, out _);
                }
            }
        }
        protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
        {
            if (!IsActive || taskWasPreviouslyQueued || task.IsCanceled || (TaskQueueDic?.ContainsKey(task) ?? true))//|| RuningTasks.Count >= MaximumConcurrencyLevel || IsCpuLimit
                return false;
            LogManage.WriteLineNewInfo($"调度信息：{nameof(TryExecuteTaskInline)}:内联执行准备[{task.Id}]：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务");
            RuningTasks?.TryAdd(task, default);
            ExecuteTask(task);
            return true;
        }
       

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void AddTask(Task task)
        {
            TaskQueue?.Insert(0, task);
            TaskQueueDic?.TryAdd(task, default);
        }
        private bool TakeOneTask(out Task? task)
        {
            task = default;
            if (TaskQueue is null) return false;
            if (TaskQueue.Count < 1)
                return false;
            task = TaskQueue?.Last();
            TaskQueue?.Remove(task!);
            return true;
        }
        private async Task Polling()
        {
            PollingTaskStartTime = DateTime.Now;
            try
            {
                while (IsActive && await PollingTask!.WaitForNextTickAsync(Tools.CurrentCancelToken!.Token))
                {
                    bool Result = taskMessages?.Writer.TryWrite(new(TaskMessageEnum.ExecuteTask, null)) ?? false;
                    LogManage.WriteLineNewInfo($"调度信息：{nameof(Polling)}:[轮询-发送执行请求][{Result}]：[cpu 占用平均值 : {CpuPerformanceAverage}],等待队列:[{TaskQueue?.Count}]个任务，执行中队列[{RuningTasks?.Count}]个任务");
                }
            }
            catch (OperationCanceledException) { }
        }
        private void RemoveTask(Task task)
        {
            if (TaskQueueDic?.TryRemove(task, out _) ?? false)
                TaskQueue?.Remove(task);
        }
        private void _Clear()
        {
            TaskQueueDic?.Clear();
            TaskQueue?.Clear();
            if (RuningTasks?.Count < 1)
                RuningTasks?.Clear();
        }
        private void _Sort()
        {
            if (QueueTasksMagage.Current is null)
                return;
            TaskQueue = TaskQueue?.Select(p => (Task: p, QueueTask: QueueTasksMagage.Current.TaskKeyQueueTaskDic[p]))
            .OrderBy(p => p.QueueTask.CurrentFragment.clip!.IsEnablePriority
                || (ClipsGroupManage.TryGetGroup(p.QueueTask.CurrentFragment.clip.Group, out ClipsGroup result) && result.MainClip.IsEnablePriority))
            .ThenBy(p => p.QueueTask.CurrentFragment.FragmentDuration).Select(p => p.Task).ToList();
        }

        protected override void QueueTask(Task task) => taskMessages?.Writer.TryWrite(new(TaskMessageEnum.AddTask, task));
        public void Sort() => taskMessages?.Writer.TryWrite(new(TaskMessageEnum.Sort, null));
        public void CancelTask(Task task) => taskMessages?.Writer.TryWrite(new(TaskMessageEnum.Remove, task));
        public void Clear()=>taskMessages?.Writer.TryWrite(new(TaskMessageEnum.Sort, null));

        

        #region Dispose
        private bool disposedValue;
        protected virtual void OnDispose()
        {
            if (!disposedValue)
            {
                OnCompleted = null;
                taskMessages!.Writer.Complete();
                PollingTask.Dispose();
                _cpuPerformanceCount!.Dispose();
                TaskQueue!.Clear();
                TaskQueueDic!.Clear();
                RuningTasks!.Clear();

                TaskQueue = null!;
                TaskQueueDic = null!;
                 _cpuPerformanceCount = null!;
                _cpuPerformanceCountValues = null!;
                RuningTasks = null!;
                PollingTask = null!;
                taskMessages = null!;
                disposedValue = true;
            }
        }
        ~TaskWorkersManage() { OnDispose(); }
        public void Dispose() { OnDispose(); GC.SuppressFinalize(this); }

        #endregion


        [Serializable]
        public class QueueTasksStartUPException : Exception
        {
            public QueueTasksStartUPException() { }
            public QueueTasksStartUPException(string message) : base(message) { }
            public QueueTasksStartUPException(string message, Exception inner) : base(message, inner) { }
            [Obsolete]
            protected QueueTasksStartUPException(
              System.Runtime.Serialization.SerializationInfo info,
              System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
        }
    }

    internal class QueueTasksMagage
    {
        public static event EventHandler<PropertyChangedEventArgs>? StaticPropertyChanged;
        private readonly static object _SyncRootSchedulerLockTaken = new object();
        public static QueueTasksMagage? Current { get; private set; }
        private static TaskWorkersManage? CurrentQueueTasksScheduler;
        private static System.Windows.Threading.DispatcherTimer? dispatcherTimer;
        private static bool m_IsRunning = false;
        public static bool IsRunning
        {
            get => m_IsRunning;
            set
            {
                if (m_IsRunning == value) return;
                m_IsRunning = value;
                StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(nameof(IsRunning)));
            }
        }
        private static IEnumerable<UIElement>? FreezeUIElements;
        private static void ProgressUpdateToUI(object? sender, EventArgs e)
        {
            if (!Tools.IsCancellationRequested)
            {
                MainWindow window = (MainWindow)Application.Current.MainWindow;
                ProgressStatistics.ProgressValue progress = ProgressStatistics.Instance.CurrentProgressValue;
                ProgressStatistics.ProgressValue CompletedProgress = ProgressStatistics.Instance.CompletedCountProgressValue;
                if (progress.RatioValue > CompletedProgress.RatioValue)
                {
                    window.StatusProgress.Maximum = progress.TotalValue;
                    window.StatusProgress.Value = progress.Progress_Value.GetValid();
                }
                else
                {
                    window.StatusProgress.Maximum = CompletedProgress.TotalValue;
                    window.StatusProgress.Value = CompletedProgress.Progress_Value.GetValid();
                }
                return;
            }
            SetThreadExecutionStateTools.Restore();
            dispatcherTimer?.Stop();
            dispatcherTimer?.Tick -= ProgressUpdateToUI;
            dispatcherTimer = null!;
        }
        public static void CloseAndClear()
        {
            lock (_SyncRootSchedulerLockTaken)
            {
                CurrentQueueTasksScheduler?.Clear();
                Tools.CurrentCancelToken?.Cancel();
                CurrentQueueTasksScheduler?.Dispose();
                CurrentQueueTasksScheduler = null;
                Tools.CurrentCancelToken?.Dispose();
                Tools.CurrentCancelToken = null;

                Application.Current.Dispatcher.Invoke(() =>
                {
                    ProgressStatistics.Clear();
                    MainWindow mainWindow = (MainWindow)Application.Current.MainWindow;
                    mainWindow.StatusProgressShowComplete("完成");
                    FreezeUIElements?.ForEach(element => element.IsEnabled = true);
                    FreezeUIElements = null;
                    IsRunning = false;
                });

                Current!.TaskKeyQueueTaskDic.Clear();
                Current!.TaskKeyQueueTaskDic = null!;
                Current.ClipQueueTasksDic.Clear();
                Current!.TaskKeyQueueTaskDic = null!;
                Current.QueueTaskKeyTaskDic.Clear();
                Current.QueueTaskKeyTaskDic = null!;
                Current.AfterprocessingOperatesDic.Clear();
                Current.AfterprocessingOperatesDic = null!;
                Current.groupMerge = null;
                Current = null;
                ClipManage.ClipList.ForEach(p => { p.IsUIFreeze = false; if (Config.AutoClearCache) p.ClearTempCheck(); });
                GroupMerge.TempCheckPath = null!;
                ScriptManage.ClearScripts();
                GC.Collect();
            }
        }

        //模块入口点
        public static void QueueStart(IEnumerable<UIElement> freezeUIElements)
        {
            ArgumentNullException.ThrowIfNull(freezeUIElements);
            ((MainWindow)Application.Current.MainWindow).OnlyStatusProgressShow();
            FreezeUIElements = freezeUIElements;
            FreezeUIElements.ForEach(element => element.IsEnabled = false);
            Tools.CurrentCancelToken = new();
            Tools.CurrentCancelToken.Token.Register(CloseAndClear);
            ScriptManage.CompilationScript();
            CurrentQueueTasksScheduler = new();
            Current = new();
            CurrentQueueTasksScheduler.OnCompleted += (s, e) => CloseAndClear();
            LogManage.WriteLineNewInfo("初始化完成");

            Task.Run(() =>
            {
                try
                {
                    Current.AddClips(ClipManage.ClipList.ToArray());
                    IsRunning = true;
                }
                catch (Exception ex)
                {
                    LogManage.WriteExceptionInfo("队列任务启动失败", ex, true);
                    CloseAndClear();
                }
            });
            SetThreadExecutionStateTools.PreventSleep();
            dispatcherTimer = new() { Interval = TimeSpan.FromMilliseconds(1000) };
            dispatcherTimer.Tick += ProgressUpdateToUI;
            dispatcherTimer.Start();
        }
        //ui移除取消任务入口
        public static void QueueTaskCancel(Clip clip)
        {
            lock (_SyncRootSchedulerLockTaken)
            {
                Application.Current.Dispatcher.BeginInvoke(() => ProgressStatistics.RemoveClip(clip.Name));

                if (!Current!.ClipQueueTasksDic.Remove(clip, out QueueTask[]? QueueTasks))
                    return;

                foreach (QueueTask item in QueueTasks)
                {
                    if (!Current.QueueTaskKeyTaskDic.Remove(item, out Task? value))
                        continue;
                    Current.TaskKeyQueueTaskDic.Remove(value, out _);
                    CurrentQueueTasksScheduler?.CancelTask(value);
                    item.Cancel();
                }
                Current.AfterprocessingOperatesDic.Remove(clip, out _);
                Current.groupMerge?.Cancel(clip);
                clip.IsUIFreeze = false;
            }
        }
        //UI添加入口
        public static void PushTask(Clip clip) => Current?.AddClips([clip]);
        public static void PushTasks(IEnumerable<Clip> clips) => Current?.AddClips(clips);
        //********************************************************************//
        public ConcurrentDictionary<Task, QueueTask> TaskKeyQueueTaskDic = new();
        public ConcurrentDictionary<QueueTask, Task> QueueTaskKeyTaskDic = new();
        public ConcurrentDictionary<Clip, QueueTask[]> ClipQueueTasksDic = new();
        public ConcurrentDictionary<Clip, AfterprocessingOperates> AfterprocessingOperatesDic = new();
        public GroupMerge? groupMerge;
        public QueueTasksMagage() { groupMerge = new GroupMerge(); }
        public bool SetQueueTaskState(Task task, QueueTask.StateEnum state)
        {
            if (!TaskKeyQueueTaskDic.ContainsKey(task))
                return false;
            TaskKeyQueueTaskDic[task].SafeSetState(state);
            return true;
        }
        public void CheckGroupClipAndExecute() => groupMerge?.CheckGroupClipAndExecute();

        private void AddClips(IEnumerable<Clip> clips)
        {
            ArgumentNullException.ThrowIfNull(groupMerge);
            ClipManage.DuplicateNameCheck();
            ClipManage.ClipListCreateFragmentIndex();
            ClipManage.NormalizationFragmentsID();
            ClipManage.UpdateModeInputIndexValues();
            LogManage.WriteLineNewInfo("数据校验完成");
            if (!GroupMerge.ClipGooupModuleArgumentsCheck())
            {
                Application.Current.Dispatcher.BeginInvoke(() =>
                {
                    ((MainWindow)Application.Current.MainWindow).StatusProgressShowError("剪辑组合并中，存在处理过程或参数不一致，详情请在LOG信息中查看");
                });
                return;
            }
            lock (_SyncRootSchedulerLockTaken)
            {
                if (CurrentQueueTasksScheduler == null)
                    return;

                List<ClipsGroup> ClipsGroups = new List<ClipsGroup>();
                foreach (Clip clip in clips)
                {
                    QueueTask[] queueTasks = clip.Fragments.Select(fragment => new QueueTask(fragment)).ToArray();
                    ClipQueueTasksDic.AddOrUpdate(clip, queueTasks, (c, old) => queueTasks);
                    AfterprocessingOperates afterprocessing;
                    if (clip.AfterprocessingFlows != null && clip.AfterprocessingFlows.Count > 0)
                    {
                        afterprocessing = new AfterprocessingOperates(clip);
                        queueTasks.ForEach(p => p.afterprocessingOperates = afterprocessing);
                        AfterprocessingOperatesDic.AddOrUpdate(clip, afterprocessing, (c, old) => afterprocessing);
                    }
                    Task task;

                    if (clip.Group != null && ClipsGroupManage.TryGetGroup(clip.Group, out ClipsGroup clipsGroup))
                        ClipsGroups.Add(clipsGroup);

                    foreach (QueueTask item in queueTasks)
                    {
                        task = item.ExecuteTask(CurrentQueueTasksScheduler);
                        TaskKeyQueueTaskDic.AddOrUpdate(task, item, (t, oldValue) => item);
                        QueueTaskKeyTaskDic.AddOrUpdate(item, task, (qt, OldValue) => task);
                    }
                    LogManage.WriteLineNewInfo($"添加任务：[{clip.Name}]");
                    clip.IsUIFreeze = true;
                }
                CurrentQueueTasksScheduler.Sort();
                groupMerge?.Preparation(ClipsGroups);
            }
        }


        [Serializable]
        public class QueueSaterUPInitException : Exception
        {
            public QueueSaterUPInitException() { }
            public QueueSaterUPInitException(string message) : base(message) { }
            public QueueSaterUPInitException(string message, Exception inner) : base(message, inner) { }
            [Obsolete]
            protected QueueSaterUPInitException(
              System.Runtime.Serialization.SerializationInfo info,
              System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
        }
    }

    internal class QueueTask
    {
        public enum StateEnum { Invalid, Ready, ConfigureComplete, Runing, Complete, GenerateFinalResulting, FinalComplete, Error }
        ProcessShell? m_processShell;
        private int m_State = 0;
        public StateEnum State => (StateEnum)m_State;
        public StateEnum SafeState => (StateEnum)Interlocked.CompareExchange(ref m_State, 0, 0);
        public bool SafeIsComparerState(StateEnum state) => SafeState == state;
        public long SafeSetState(StateEnum state) => Interlocked.Exchange(ref m_State, (int)state);
        public Fragment CurrentFragment;
        public AfterprocessingOperates? afterprocessingOperates;
        public AdvancedParametersSchemeModule[] Modules;
        public SuccessAndProgress[] successAndProgresses;
        public CancellationTokenSource cancellationTokenSource;
        private CancellationTokenSource LinkedCancellationTokenSource;
        public bool IsCancellationRequested => Tools.IsCancellationRequested || (LinkedCancellationTokenSource?.IsCancellationRequested ?? true);
        public QueueTask(Fragment fragment)
        {
            ArgumentNullException.ThrowIfNull(fragment, nameof(fragment));
            ArgumentNullException.ThrowIfNull(fragment.clip, nameof(fragment.clip));
            CurrentFragment = fragment;
            Modules = CurrentFragment.clip.Flows.Select(p => p.DeepCopy()).ToArray();
            successAndProgresses = new SuccessAndProgress[Modules.Length];
            AdvancedParametersSchemeModule CurrentModule;
            for (int i = 0; i < Modules.Length; i++)
            {
                CurrentModule = Modules[i];
                if (!CurrentModule.GetInputs(out ParametersSign[] Inputs))
                    throw new ArgumentException($"剪辑[{fragment.clip.Name}]->片段[{fragment.Name}]->流程[{CurrentModule.SchemeName}] 缺少输入参数");

                //处理输入
                foreach (ParametersSign CurrentInputParame in Inputs)
                {
                    if (!Tools.InputToIndex(CurrentInputParame.Parameter, out int SelectIndex))
                        throw new ArgumentException($"剪辑[{fragment.clip.Name}]->片段[{fragment.Name}]->流程[{CurrentModule.SchemeName}]->[{CurrentInputParame.SignName}]:输入参数异常，不是一个可以转换的值");
                    //当前流是否队列首个流 或者选择的输入是否是源的输入
                    if (i < 1 || SelectIndex < 0)
                        CurrentInputParame.Parameter = fragment.InputPath;
                    else
                    {
                        if (SelectIndex >= i)
                            throw new ArgumentException($"剪辑[{fragment.clip.Name}]->片段[{fragment.Name}]->流程[{CurrentModule.SchemeName}]->[{CurrentInputParame.SignName}]" +
                                "流输入选择错误,在流程中目标流晚于当前流，目标流的输出结果尚未产生，无法作为当前流的输入");
                        CurrentInputParame!.Parameter = Modules[SelectIndex].GetOutput().Parameter;
                    }
                }

                //处理输出
                string Extension = CurrentModule.GetOutput().Parameter.Trim();
                if (!Extension.StartsWith('.'))
                    Extension = '.' + Extension;

                string path = fragment.clip.TempCacheDirectory;
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);

                CurrentModule.GetOutput().Parameter = Path.Combine(path, $"{fragment.Name}_Flow_{i}{Extension}");
                //处理时间
                if (CurrentModule.GetParametersSign(ParametersSign.ETime, out ParametersSign? ETime))
                {
                    if (CurrentModule.IsDurationMode)
                        ETime!.Parameter = Tools.GetTimeSpanToString(fragment.FragmentDuration);
                    else ETime!.Parameter = fragment.EndTimeValue;
                }
                if (CurrentModule.GetParametersSign(ParametersSign.STime, out ParametersSign? STime))
                    STime!.Parameter = fragment.StartTimeValue;

                successAndProgresses[i] = new SuccessAndProgress(CurrentModule, fragment);

                m_State = (int)StateEnum.Ready;
            }
            cancellationTokenSource = new();
            LinkedCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, Tools.CurrentCancelToken!.Token);
        }

        public void Cancel()
        {
            cancellationTokenSource.Cancel();
            cancellationTokenSource.Dispose();
            cancellationTokenSource = null!;
            LinkedCancellationTokenSource.Dispose();
            LinkedCancellationTokenSource = null!;
            m_processShell?.Dispose();
            m_processShell = null;
            afterprocessingOperates?.Cancel();
            successAndProgresses.ForEach(p => p.Dispose());
            Modules = null!;
            CurrentFragment = null!;
        }

        private void ProcessShellProcessExecute(string ProcessName, string Args, Action<string?>? OutputReceived, Action<string?>? ErrorReceived)
        {
            m_processShell = new ProcessShell();
            m_processShell.ExecuteWaitForExit(ProcessName, Args, OutputReceived, ErrorReceived);
        }

        private void ExecuteModule(AdvancedParametersSchemeModule module, SuccessAndProgress successAndProgress)
        {
            string InFileFullPath = module.GetInput().Parameter;
            string OutFileFullPath = module.GetOutput().Parameter;
            successAndProgress.Init();
            if (IsCancellationRequested) return;
            successAndProgress.WriteLineNewInfo($"剪辑[{CurrentFragment.clip!.Name}]->片段[{CurrentFragment.Name}]->流程[{module.SchemeName}]");
            if (string.IsNullOrEmpty(InFileFullPath) || !File.Exists(InFileFullPath))
            {
                successAndProgress.ErrorInfo = $"[{InFileFullPath}]输入文件不存在";
                successAndProgress.CompletedTimingSeconds = successAndProgress.TotalSeconds;
                LogManage.WriteLineNewInfo(successAndProgress.ErrorInfo, true);
                return;
            }
            if (string.IsNullOrEmpty(OutFileFullPath) || !Directory.Exists(Path.GetDirectoryName(OutFileFullPath)))
            {
                successAndProgress.ErrorInfo = $"[{OutFileFullPath}]输出路径不存在";
                successAndProgress.CompletedTimingSeconds = successAndProgress.TotalSeconds;
                LogManage.WriteLineNewInfo(successAndProgress.ErrorInfo, true);
                return;
            }
            if (IsCancellationRequested) return;
            if (File.Exists(OutFileFullPath))
                File.Delete(OutFileFullPath);

            string args = module.GenerateCommandArgument();
            successAndProgress.WriteLineNewInfo($"{module.ProcessorName} {args}");
            if (IsCancellationRequested) return;
            CallShell.ShellTypeProcessNameIFSet(module);


            successAndProgress.EnableWriteLog = module.EnableSkipOutputSign;


            LogManage.WriteLineNewInfo($"执行:[{CurrentFragment.clip.Name}->{CurrentFragment.Name}->{module.ProcessorName}]");
            if (InternalProcessorSelector.GetSelector(module, out Action<AdvancedParametersSchemeModule, SuccessAndProgress> ProcessExecute))
                ProcessExecute?.Invoke(module, successAndProgress);
            else
                ProcessShellProcessExecute(module.ProcessorName, args, successAndProgress.SuccessValidated, successAndProgress.SuccessValidated);
            if (!successAndProgress.IsSuccess)
                successAndProgress.ErrorInfo = $"处理错误:参数:[{module.ProcessorName}] [{args}]";
            if (IsCancellationRequested) return;
            successAndProgress.CompletedTimingSeconds = successAndProgress.TotalSeconds;

           
            if (successAndProgress.EnableWriteLog)
                File.WriteAllText(OutFileFullPath, successAndProgress.Log);


            LogManage.WriteLineNewInfo(successAndProgress.Log);
            successAndProgress.ReleaseScript();
            if (IsCancellationRequested) return;
            if (!successAndProgress.IsSuccess)
                throw new AdvancedParametersSchemeModuleExecuteException($"{successAndProgress.ErrorInfo} Log [{successAndProgress.Log}]");
            ArgumentNullException.ThrowIfNull(QueueTasksMagage.Current, "[QueueTasksMagage.Current]");
            SafeSetState(StateEnum.ConfigureComplete);
        }
        private void Execute()
        {
            if (IsCancellationRequested)
                return;
            for (int i = 0; i < Modules.Length; i++)
            {
                if (IsCancellationRequested)
                    return;
                try { ExecuteModule(Modules[i], successAndProgresses[i]); }
                catch (Exception exc) { throw new AdvancedParametersSchemeModuleExecuteException($"异常来自:[{CurrentFragment.clip!.Name}]->[{CurrentFragment.Name}]->{Modules[i].SchemeName}:{successAndProgresses[i].ErrorInfo}", exc); }
            }
        }
        
        //剪辑最终阶段-剪辑中的全部片段完成-执行后处理操作
        private bool GenerateFinalResult()
        {
            ArgumentNullException.ThrowIfNull(QueueTasksMagage.Current, "[QueueTasksMagage.Current]");
            ArgumentNullException.ThrowIfNull(CurrentFragment.clip, $"[Fragment({CurrentFragment.Name}).clip]");
            lock (CurrentFragment.clip)
            {
                QueueTask[] ClipQueueTasks = QueueTasksMagage.Current.ClipQueueTasksDic[CurrentFragment.clip];
                if (ClipQueueTasks.Any(p => !p.SafeIsComparerState(StateEnum.Complete)))
                    return false;
                ClipQueueTasks.ForEach(p => p.SafeSetState(StateEnum.GenerateFinalResulting));
            }

            //生成输出路径
            string TarPath = CurrentFragment.clip!.Flows.Last().GetOutput().Parameter;
            if (!TarPath.StartsWith('.'))
                TarPath = "." + TarPath;
            TarPath = Path.Combine(CurrentFragment.clip.OutDirectory, $"{CurrentFragment.clip.Name}{TarPath}");
            LogManage.WriteLineNewInfo($"构造输出路径{TarPath}");
            Tools.CheckDuplicateNameAndLegal(ref TarPath, true);
            CurrentFragment.clip.FileWritePath = TarPath;

            //只有一个片段
            if (CurrentFragment.clip.Count < 2)
            {
                //执行后处理
                if (afterprocessingOperates != null)
                {
                    if (IsCancellationRequested) return false;
                    try { afterprocessingOperates.Execute(Modules.Last().GetOutput().Parameter); }
                    catch (Exception exc) { throw new AfterprocessingOperates.AfterprocessingOperatesException($"[{CurrentFragment.clip}]执行后处理过程错误,执行中断", exc); }
                    if (IsCancellationRequested) return false;
                    TarPath = afterprocessingOperates.taskFlows.Last().ThisFragment.TempWritePath;
                    CurrentFragment.clip.FileWritePath = TarPath;
                    if (!File.Exists(CurrentFragment.clip.FileWritePath))
                        throw new AfterprocessingOperates.AfterprocessingOperatesException($"执行后处理失败:[{CurrentFragment.clip.Name}]->{TarPath}");
                }
                //直接移动
                else
                {
                    LogManage.WriteLineNewInfo($"移动文件:[{Modules.Last().GetOutput().Parameter}->{TarPath}]");
                    if (!Tools.CheckDirectoryPath(Path.GetDirectoryName(TarPath)!, out string m_err))
                        throw new DirectoryNotFoundException($"目标目录参数异常[{m_err}]");
                    if (IsCancellationRequested) return false;
                    File.Move(Modules.Last().GetOutput().Parameter, TarPath);
                    if (IsCancellationRequested) return false;
                    if (!File.Exists(TarPath))
                        throw new FileNotFoundException($"移动失败:[{CurrentFragment.clip.Name}]->{TarPath}");
                }
            }
            //多片段
            else
            {
                string MergeInfoPath = Path.Combine(CurrentFragment.clip!.TempCacheDirectory, $"{CurrentFragment.clip!.Name}_Marge.txt");
                StringBuilder sb = new();
                //获取所有片段的最后一个流的输出路径并写入合并文档
                QueueTasksMagage.Current.ClipQueueTasksDic[CurrentFragment.clip].Select(p => p.Modules.Last().GetOutput().Parameter).ForEach(path =>
                {
                    sb.AppendLine($"file '{path}'");
                });
                if (IsCancellationRequested) return false;
                File.WriteAllText(MergeInfoPath, sb.ToString());
                MergeInfo mi = new();
                //后处理
                if (afterprocessingOperates != null)
                {
                    try
                    {
                        //设置合并路径
                        TarPath = Path.ChangeExtension(MergeInfoPath, CurrentFragment.clip!.Flows.Last().GetOutput().Parameter);
                        if (Tools.CheckDuplicateNameAndLegal(ref TarPath, true))
                        {
                            LogManage.WriteLineNewInfo($"后处理前合并文件:[\r\n{sb.ToString()}\r\n]->{TarPath}]");
                            if (IsCancellationRequested) return false;
                            ProcessShellProcessExecute(Config.CoreProcessor, Tools.FFmpegMergeArguments(MergeInfoPath, TarPath), mi.SetTaskInfo, mi.SetTaskInfo);
                            if (IsCancellationRequested) return false;
                        }
                        else throw new ArgumentException($"输出路径参数值[\"{TarPath}\"]非法或根目录不存在");
                        if (mi.IsError)
                            throw new MergeException($"[{CurrentFragment.clip.Name}]合并执行异常:详情:\r\n{Tools.FFmpegMergeArguments(MergeInfoPath, TarPath)}\r\n{{{mi}\r\n}}");
                    }
                    catch (Exception exc) { throw new MergeException($"[{CurrentFragment.clip.Name}]执行合并过程错误,执行中断", exc); }
                    try { afterprocessingOperates.Execute(TarPath); }
                    catch (Exception exc) { throw new AfterprocessingOperates.AfterprocessingOperatesException($"[{CurrentFragment.clip.Name}]执行后处理过程错误,执行中断", exc); }
                    if (IsCancellationRequested)
                        return false;
                    TarPath = afterprocessingOperates.taskFlows.Last().ThisFragment.TempWritePath;
                    CurrentFragment.clip.FileWritePath = TarPath;
                    if (!File.Exists(CurrentFragment.clip.FileWritePath))
                        throw new AfterprocessingOperates.AfterprocessingOperatesException($"执行后处理失败:[{CurrentFragment.clip.Name}]->{TarPath}");
                }
                //直接合并
                else
                {
                    if (!Tools.CheckDirectoryPath(Path.GetDirectoryName(TarPath)!, out string m_err))
                        throw new DirectoryNotFoundException($"目标目录参数异常[{m_err}]");
                    LogManage.WriteLineNewInfo($"合并文件:[\r\n{sb.ToString()}\r\n]->{TarPath}]");
                    if (IsCancellationRequested) return false;
                    ProcessShellProcessExecute(Config.CoreProcessor, Tools.FFmpegMergeArguments(MergeInfoPath, TarPath), mi.SetTaskInfo, mi.SetTaskInfo);
                    if (IsCancellationRequested) return false;
                    if (mi.IsError)
                        throw new MergeException($"[{CurrentFragment.clip}]合并执行异常:详情:\r\n{Tools.FFmpegMergeArguments(MergeInfoPath, TarPath)}\r\n{{{mi}\r\n}}");
                }
            }
            return true;
        }
        private void MainExecute()
        {
            SafeSetState(StateEnum.Runing);
            try
            {
                Execute();
                SafeSetState(StateEnum.Complete);
                if (IsCancellationRequested) return;
                if (!GenerateFinalResult())
                    return;
                SafeSetState(StateEnum.FinalComplete);
                _ = Application.Current.Dispatcher.BeginInvoke(() => CurrentFragment.clip!.CompletionStatus = CompletionStatusEnum.Success);
                if (IsCancellationRequested) return;
                QueueTasksMagage.Current?.CheckGroupClipAndExecute();
            }
            catch (GroupMerge.GroupMergeException gmexc)
            {
                LogManage.WriteExceptionInfo("队列执行,组合并异常:", gmexc, true);
            }
            catch (Exception exc)
            {
                SafeSetState(StateEnum.Error);
                _ = Application.Current.Dispatcher.BeginInvoke(() => CurrentFragment.clip!.CompletionStatus = CompletionStatusEnum.Fail);
                LogManage.WriteExceptionInfo("队列执行异常:", exc, true);
            }
        }
        public Task ExecuteTask(TaskScheduler taskScheduler) => Task.Factory.StartNew(MainExecute, LinkedCancellationTokenSource.Token, TaskCreationOptions.LongRunning, taskScheduler);


        [Serializable]
        public class AdvancedParametersSchemeModuleExecuteException : Exception
        {
            public AdvancedParametersSchemeModuleExecuteException() { }
            public AdvancedParametersSchemeModuleExecuteException(string message) : base(message) { }
            public AdvancedParametersSchemeModuleExecuteException(string message, Exception inner) : base(message, inner) { }
            [Obsolete]
            protected AdvancedParametersSchemeModuleExecuteException(
              System.Runtime.Serialization.SerializationInfo info,
              System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
        }
        [Serializable]
        public class MergeException : Exception
        {
            public MergeException() : base("FFmpeg未能完成合并") { }
            public MergeException(string message) : base($"FFmpeg未能完成合并:{message}") { }
            public MergeException(string message, Exception inner) : base(message, inner) { }
            [Obsolete]
            protected MergeException(
              System.Runtime.Serialization.SerializationInfo info,
              System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
        }
        public class MergeInfo
        {
            public bool IsError { get; private set; } = true;
            private StringBuilder StringBuilder = new StringBuilder();
            private Regex ProgressExpression;
            SuccessAndProgress? successAndProgress;
            public MergeInfo(SuccessAndProgress? successAndProgress = null)
            {
                ProgressExpression = new(Config.MainCoreProcessor.GetProgressValueExpression, RegexOptions.Compiled);
                this.successAndProgress = successAndProgress;
            }
            public void SetTaskInfo(string? value)
            {
                if (string.IsNullOrWhiteSpace(value))
                    return;
                successAndProgress?.SuccessValidated(value);
                if (Config.FFmpegSuccessValidated.IsMatch(value))
                    IsError = false;
                else if (!string.IsNullOrWhiteSpace(value) && !ProgressExpression.IsMatch(value))
                    StringBuilder.AppendLine(value);
            }
            public override string ToString() => StringBuilder.ToString();
        }

    }

}
